#pragma once
#include "stdafx.h"
#define COMP_DUMP_FILE "./log/ComponentDump.txt"

/*
TODO:
	1. Use TMP instead of boost::any when send message.
	benefit: type check from run time to compile time.
	2. Complete remove and destroy component.
*/

class Component;
class Object;

class Manager
{
private:
	Manager(const Manager&);
	
public:
	typedef boost::shared_ptr<Manager> sPtr;
	typedef boost::unordered_map< ObjectName, ObjPtr, boost::hash<int> > ObjectMap;
	typedef RequestMap GlobalRequestMap;
	typedef LockMap GlobalRequestLockMap;

	Manager();
	virtual ~Manager();

	//Add object in Manager
	void AddObject(const ObjPtr & );

	//Add component to manager, this component also added to object.
	//After component added, call AddedToObject function to regist all 
	//the request this component need. Finally, search if there are any
	//other components request this one.
	void AddComponent(const ObjectName &, const CompPtr & );

	//Regist global request, if this request is locked, then regist it later.
	//Also regist this request in the object. If is an component request, search
	//All existing component, then call the callback function if need.
	//i.e.(necessity of lock)
	//1. When you add a new component A, and component B request this component.
	//In B's callback function, you create an other component also named A. The 
	//program will in dead loop.
	//2. Prevent iterator invalid when you add component in a callback function.
	void RegisterGlobalRequest(const ComponentRequest &, const RegisteredComponent &);

	//Register a local request, see RegisterGlobalRequest for more details.
	void RegisterLocalRequest(const ComponentRequest &, const RegisteredComponent &);

	//Send a global message
	void SendMessage(const MsgId& msg, const boost::any payload);

	//Send a global message, if this message has been locked then raise an error.
	//otherwise, call the callback function if there are any existing request match this message
	void SendGlobalMessage(const ComponentRequest &, const Message &);

	//Send a local message to specifical object.
	void SendMessageToObject(const ComponentRequest &, const Message & msg, const ObjectName &);

	//abandon?
	void DestoryComponent(const CompName&, const CompId&);

#ifdef _DEBUG
	void DumpObjects(ObjectMap::value_type objs);
	void DumpComponents(CompMap::value_type);
	void DumpMessageReqs(std::pair<const RequestId,CallbackList> msg);
	void DumpComponentReqs(std::pair<const RequestId,CallbackList> comp);
	void DumpMessageLocks(std::pair<const RequestId,RequestLock>);
	void DumpComponentLocks(std::pair<const RequestId,RequestLock>);
	void DumpRequests(GlobalRequestMap::value_type reqs);
	void DumpRequestLocks(GlobalRequestLockMap::value_type);
	void Dump();

	ofstream m_dumpFile;
#endif

private:

	GlobalRequestMap fGlobalRequests;

	void ActivateLock(const ComponentRequest& );
	void ReleaseLock(const ComponentRequest& );

	// number of active locks
	int m_nLocks;

	// list of locked request id's
	GlobalRequestLockMap m_requestLocks;

	// list of objects with their id's
	ObjectMap m_objects;

	// mapping of objects to their unique name identified
	CompMap m_components;
};

